package busquedasheuristicas.primeromejor;

import java.util.ArrayList;

import busquedasciegas.EstadoPuzzle;

public class EstadoHeuristica extends EstadoPuzzle implements Comparable<EstadoHeuristica>{

	int h;
	EstadoHeuristica padre;
	
	private EstadoHeuristica hijo1, hijo2, hijo3, hijo4;
	private ArrayList<EstadoHeuristica> descendientes;
	
	public EstadoHeuristica(ArrayList<Integer> tablero, int[] meta) {
		super(tablero);
		calcularHeuristica(meta);
		this.descendientes = new ArrayList<EstadoHeuristica>();
	}
	
	public EstadoHeuristica(int[] tablero, EstadoHeuristica padre) {
		super(tablero, padre);
		this.key = new Key(tablero);
		this.padre = padre;
		this.descendientes = new ArrayList<EstadoHeuristica>();
		this.visitado = false;
		hallarHueco();
	}
	
	/**
	 * Calcula el valor de la heuristica para el estado actual.
	 * Utiliza el nodo meta para poder calcular dicho valor
	 * (numero de cuadrados en desorden respecto al numero de los
	 * mismos en el estado meta, por ejemplo)
	 * @param meta Estado meta.
	 */
	private void calcularHeuristica(int[] meta) {
		for (int i = 0; i < meta.length; i++) {
			if (this.key.tablero[i] == meta[i])
				h++;
		}
		h = (meta.length-1) - h;
		
	}
	
	/**
	 * Esta función aplica los operadores a un estado
	 * con el fin de obtener nuevos estados (descendientes).
	 * @return Una lista con los hijos del estado actual (this).
	 */
	public ArrayList<EstadoHeuristica> generarDescendientes(int[] meta){
	
		temp = this.key.tablero.clone();
		this.descendientes.clear();
		
		
		if ((iHueco == 0) && (jHueco == 0)){
			temp[0] = this.key.tablero[1];
			temp[1] = 0;
			hijo1 = new EstadoHeuristica(temp, this);
			hijo1.calcularHeuristica(meta);
			descendientes.add(hijo1);

			temp = this.key.tablero.clone();
			temp[0] = this.key.tablero[lado];
			temp[lado] = 0;
			hijo2 = new EstadoHeuristica(temp, this);
			hijo2.calcularHeuristica(meta);
			
			descendientes.add(hijo2);
	
		}
		else if ((iHueco == 0) && (jHueco == lado-1)){
			temp[lado-1] = this.key.tablero[1];
			temp[1] = 0;
			hijo1 = new EstadoHeuristica(temp, this);
			hijo1.calcularHeuristica(meta);
			
			temp = this.key.tablero.clone();
			temp[lado-1] = this.key.tablero[lado+lado-1];
			temp[lado+lado-1] = 0;
			hijo2 = new EstadoHeuristica(temp, this);
			hijo2.calcularHeuristica(meta);
			
			descendientes.add(hijo1);
			descendientes.add(hijo2);
		}
		else if ((iHueco == lado-1) && (jHueco == 0)){
			temp[lado*(lado-1)] = this.key.tablero[lado*(lado-2)];
			temp[lado*(lado-2)] = 0;
			hijo1 = new EstadoHeuristica(temp, this);
			hijo1.calcularHeuristica(meta);
			
			temp = this.key.tablero.clone();
			temp[lado*(lado-1)] = this.key.tablero[(lado*(lado-1))+1];
			temp[(lado*(lado-1))+1] = 0;
			hijo2 = new EstadoHeuristica(temp, this);
			hijo2.calcularHeuristica(meta);
			
			descendientes.add(hijo1);
			descendientes.add(hijo2);
			
		}
		else if ((iHueco == lado-1) && (jHueco == lado-1)){
			temp[(lado*(lado-1))+(lado-1)] = this.key.tablero[(lado*(lado-2))+(lado-1)];
			temp[(lado*(lado-2))+(lado-1)] = 0;
			hijo1 = new EstadoHeuristica(temp, this);
			hijo1.calcularHeuristica(meta);
			
			temp = this.key.tablero.clone();
			temp[(lado*(lado-1))+(lado-1)] = this.key.tablero[(lado*(lado-1))+(lado-2)];
			temp[(lado*(lado-1))+(lado-2)] = 0;
			hijo2 = new EstadoHeuristica(temp, this);
			hijo2.calcularHeuristica(meta);
			
			descendientes.add(hijo1);
			descendientes.add(hijo2);
		}
		else if (((1 <= iHueco) && (iHueco <= lado-2)) &&
				((1 <= jHueco) && (jHueco <= lado-2))){
			temp[(lado*iHueco)+jHueco] = this.key.tablero[(lado*(iHueco+1))+jHueco];
			temp[(lado*(iHueco+1))+jHueco] = 0;
			hijo1 = new EstadoHeuristica(temp, this);
			hijo1.calcularHeuristica(meta);
			
			temp = this.key.tablero.clone();
			temp[(lado*iHueco)+jHueco] = this.key.tablero[(lado*(iHueco-1))+jHueco];
			temp[(lado*(iHueco-1))+jHueco] = 0;
			hijo2 = new EstadoHeuristica(temp, this);
			hijo2.calcularHeuristica(meta);
			
			temp = this.key.tablero.clone();
			temp[(lado*iHueco)+jHueco] = this.key.tablero[(lado*iHueco)+(jHueco-1)];
			temp[(lado*iHueco)+(jHueco-1)] = 0;
			hijo3 = new EstadoHeuristica(temp, this);
			hijo3.calcularHeuristica(meta);
			
			temp = this.key.tablero.clone();
			temp[(lado*iHueco)+jHueco] = this.key.tablero[(lado*iHueco)+(jHueco+1)];
			temp[(lado*iHueco)+(jHueco+1)] = 0;
			hijo4 = new EstadoHeuristica(temp, this);
			hijo4.calcularHeuristica(meta);
			
			descendientes.add(hijo1);
			descendientes.add(hijo2);
			descendientes.add(hijo3);
			descendientes.add(hijo4);
		}
		else{
			if (iHueco == 0){
				temp[(lado*iHueco)+jHueco] = this.key.tablero[(lado*iHueco)+(jHueco-1)];
				temp[(lado*iHueco)+(jHueco-1)] = 0;
				hijo1 = new EstadoHeuristica(temp, this);
				hijo1.calcularHeuristica(meta);
				
				temp = this.key.tablero.clone();
				temp[(lado*iHueco)+jHueco] = this.key.tablero[(lado*iHueco)+(jHueco+1)];
				temp[(lado*iHueco)+(jHueco+1)] = 0;
				hijo2 = new EstadoHeuristica(temp, this);
				hijo2.calcularHeuristica(meta);
				
				temp = this.key.tablero.clone();
				temp[(lado*iHueco)+jHueco] = this.key.tablero[(lado*(iHueco+1))+jHueco];
				temp[(lado*(iHueco+1))+jHueco] = 0;
				hijo3 = new EstadoHeuristica(temp, this);
				hijo3.calcularHeuristica(meta);
				
				descendientes.add(hijo1);
				descendientes.add(hijo2);
				descendientes.add(hijo3);
			}
			else if (iHueco == lado-1){
				temp[(lado*iHueco)+jHueco] = this.key.tablero[(lado*iHueco)+(jHueco-1)];
				temp[(lado*iHueco)+(jHueco-1)] = 0;
				hijo1 = new EstadoHeuristica(temp, this);
				hijo1.calcularHeuristica(meta);
				
				temp = this.key.tablero.clone();
				temp[(lado*iHueco)+jHueco] = this.key.tablero[(lado*iHueco)+(jHueco+1)];
				temp[(lado*iHueco)+(jHueco+1)] = 0;
				hijo2 = new EstadoHeuristica(temp, this);
				hijo2.calcularHeuristica(meta);
				
				temp = this.key.tablero.clone();
				temp[(lado*iHueco)+jHueco] = this.key.tablero[(lado*(iHueco-1))+jHueco];
				temp[(lado*(iHueco-1))+jHueco] = 0;
				hijo3 = new EstadoHeuristica(temp, this);
				hijo3.calcularHeuristica(meta);
				
				descendientes.add(hijo1);
				descendientes.add(hijo2);
				descendientes.add(hijo3);
			}
			else if (jHueco == 0){
				temp[(lado*iHueco)+jHueco] = this.key.tablero[(lado*(iHueco-1))+jHueco];
				temp[(lado*(iHueco-1))+jHueco] = 0;
				hijo1 = new EstadoHeuristica(temp, this);
				hijo1.calcularHeuristica(meta);
				
				temp = this.key.tablero.clone();
				temp[(lado*iHueco)+jHueco] = this.key.tablero[(lado*(iHueco+1))+jHueco];
				temp[(lado*(iHueco+1))+jHueco] = 0;
				hijo2 = new EstadoHeuristica(temp, this);
				hijo2.calcularHeuristica(meta);
				
				temp = this.key.tablero.clone();
				temp[(lado*iHueco)+jHueco] = this.key.tablero[(lado*iHueco)+(jHueco+1)];
				temp[(lado*iHueco)+(jHueco+1)] = 0;
				hijo3 = new EstadoHeuristica(temp, this);
				hijo3.calcularHeuristica(meta);
				
				descendientes.add(hijo1);
				descendientes.add(hijo2);
				descendientes.add(hijo3);
			}
			else if (jHueco == lado-1){
				temp[(lado*iHueco)+jHueco] = this.key.tablero[(lado*(iHueco-1))+jHueco];
				temp[(lado*(iHueco-1))+jHueco] = 0;
				hijo1 = new EstadoHeuristica(temp, this);
				hijo1.calcularHeuristica(meta);
				
				temp = this.key.tablero.clone();
				temp[(lado*iHueco)+jHueco] = this.key.tablero[(lado*(iHueco+1))+jHueco];
				temp[(lado*(iHueco+1))+jHueco] = 0;
				hijo2 = new EstadoHeuristica(temp, this);
				hijo2.calcularHeuristica(meta);
				
				temp = this.key.tablero.clone();
				temp[(lado*iHueco)+jHueco] = this.key.tablero[(lado*iHueco)+(jHueco-1)];
				temp[(lado*iHueco)+(jHueco-1)] = 0;
				hijo3 = new EstadoHeuristica(temp, this);
				hijo3.calcularHeuristica(meta);
				
				descendientes.add(hijo1);
				descendientes.add(hijo2);
				descendientes.add(hijo3);
			}
			
		}
		return descendientes;
		
	}


	public static void main(String[] args) {
		ArrayList<Integer> inicial = new ArrayList<Integer>();
		int[] meta = new int[9];
		meta[0] = 1;
		meta[1] = 2;
		meta[2] = 3;
		meta[3] = 8;
		meta[4] = 0;
		meta[5] = 4;
		meta[6] = 7;
		meta[7] = 6;
		meta[8] = 5;

		// estado inicial
		inicial.add(2);
		inicial.add(8);
		inicial.add(3);
		inicial.add(1);
		inicial.add(6);
		inicial.add(4);
		inicial.add(7);
		inicial.add(0);
		inicial.add(5);

		EstadoHeuristica e = new EstadoHeuristica(inicial, meta);
		System.out.println(e.generarNodoInicial(9, true));
		System.out.println("Heuristica: " + e.h);
	}

	@Override
	public int compareTo(EstadoHeuristica estado) {   
	    return this.h - estado.h;    
	}

}
